<?php

/** 
 * Copyright (c) 2012, Jiehun.com.cn Inc. All Rights Reserved
 * @author zhanghaiyang@jiehun.com.cn
 * @date 2012-4-26
 * @version 1.0 
 * @brief 
 *  
 **/

final class Sfilter
{
	private $_conf;
	private $_connect;
	private $_javaApis=array("request","html","senWords");
	private $_sep="{HTMLTEXT_FILTER_SEPARATE}";
	function __construct($conf)
	{
		$this->_conf = $conf;
		if (empty($this->_conf)) {
			throw new Exception('Socket.EmptyConf');
		}
	}
	
	/**
	 * 建立socket链接
	 *
	 */
	private function getConnect()
	{
		$this->_connect = @fsockopen($this->_conf['server'],$this->_conf['port'], $errno, $errstr, $this->_conf['connect_timeout']);
		//三次重试
		for($i=0;$i<$this->_conf['retry'];$i++)
		{
			if(!$this->_connect)
			{
				$this->_connect = @fsockopen($this->_conf['server'],$this->_conf['port'], $errno, $errstr, $this->_conf['connect_timeout']);
			}
			else
			{
				break;
			}
		}
	}
	
	/**
	 * 向socket java模块发送数据
	 *@param $data=array(
	 * '0'=>array(
	 * 				'content'=>content,
	 * 				'javaApi'=>javaApi,
	 * 				'method'=>method
	 				'type'=>{0,1} 1全部过滤 0指定过滤
	 * 			))
	 */
	private function sendData($data)
	{
		$sendStr='';
		if(!$this->_connect) throw new Exception("Socket.sendData connect failed");
		if(!is_array($data))
		{
			throw new Exception("Socket.sendData data error");
		}
		
		foreach($data as $k=>$v)
		{
			if(!isset($v['javaApi']) || empty($v['javaApi']))  $v['javaApi']=$this->_javaApis['0'];
			if(!isset($v['method']) || empty($v['method']))  $v['method']="tidy";
			if(!isset($v['content']) || empty($v['content'])) $v['content']="";
			$v['type'] = isset($v['type'])?$v['type']:0;//过滤类型 1 全部过滤 0指定过滤
			
			$sendStr.=$v['javaApi']."/".$v['method'].":".$v['type']."\r\n".$v['content']."\r\n\1\r\n";
		}
		fputs($this->_connect,$sendStr."\0\r\n");
	}
	
	/**
	 * 接收socket java模块返回的数据
	 *
	 */
	private function receiveData()
	{
		if(!$this->_connect) throw new Exception("Socket.receiveData connect failed");
		$ret = '';
		$res = array();
		while(!feof($this->_connect)) {
			if(strpos($ret,"\1")){
				$res[]=str_replace("\1","",$ret);
				$ret='';
		    }
			if(strpos($ret,"\0")){
				break;
		    }
		    $ret .= fgets($this->_connect, $this->_conf['read_size']);
		}
		return $res;
	}
	
	/**
	 * 关闭socket链接
	 *
	 */
	private function close()
	{
		if($this->_connect) fclose($this->_connect);
	}
	
	/**
	 * 判断是否是有效的java api
	 */
	private function isJavaApi($javaApi)
	{
		if(in_array($javaApi,$this->_javaApis))
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	/**
	 * 获取规范化的html
	 *
	 * @param array $data=array(key=>value))
	 * @return array
	 */
	function filterHtmls($data)
	{
		$sendData=array();
		if(!is_array($data)) throw new Exception("Socket.filterHtmls data must be an array");
		foreach($data as $k => $v)
		{
			$sendData[$k]['content']=$v;
			$sendData[$k]['javaApi']=$this->_javaApis['0'];
			$sendData[$k]['method']='filterHtmls';
		}
		return $this->get($sendData);
	}
	
	/**
	 * 检测是包含的敏感词及联系方式
	 *
	 * @param array $data=array(key=>value))
	 * @return array
	 */
	function filterWords($data)
	{
		$sendData=array();
		if(!is_array($data)) throw new Exception("Socket.filterWords data must be an array");
		foreach($data as $k => $v)
		{
			$sendData[$k]['content']=$v['value'];
			$sendData[$k]['javaApi']=$this->_javaApis['0'];
			$sendData[$k]['method']='filterWords';
			$sendData[$k]['type'] = isset($v['type'])?$v['type']:0;
		}
		return $this->get($sendData);
	}
	
	/**
	 * 获取socket java api处理过的数据
	 * java api : senWords || html || request(包括senWords检测和html规范)
	 * @param array $data 待处理的数据
	 * @return json
	 */
	private function get($data)
	{
		$this->getConnect();
		if(!$this->_connect) return $this->imitateData($data);
		if(!is_array($data)) throw new Exception("Socket.get data must be an array");
		foreach($data as $k => $v)
		{
			if(!isset($v['content'])) throw new Exception("Socket.get data[content] key not exitst");
			if(empty($v['content'])) $data[$k]['content']="hbh_empty";
			$method=$v['method'];
			$javaApi=$v['javaApi'];
		}

		$res=array();
		
		if(!$this->isJavaApi($javaApi))
		{
			throw new Exception("Socket.get java api invalid");
		}
		
		//发送请求
		$this->sendData($data);
		
		//接收数据
		$ret =$this->receiveData();

		if(!empty($ret))
		{
			foreach($ret as $k => $v)
			{
				//解析数据
				switch ($method)
				{
					case "filterHtmls":
						if(trim($v)=='hbh_empty')
						{
							$res[]='';
						}
						else
						{
							$res[]=$v;
						}
						break;
					case "filterWords":
						$res[]=$this->JsonToArray($v);
						break;
				}
				
			}
		}

		//关闭socket请求
		$this->close();
		return $res;
	}
	

	function JsonToArray($jsonStr)
	{
		$filter=json_decode(trim($jsonStr));

		$res['hasEmail']=$filter->hasEmail;
		$res['hasPhone']=$filter->hasPhone;
		$res['hasQQ']	=$filter->hasQQ;
		$res['hasWords']=$filter->hasWords;
		return $res;
	}

	/**
	 * 敏感词列表
	 * @return string 词与词之间用英文逗号分隔
	 */
	function senWordlist()
	{
		$words="";
		//获取链接
		$this->getConnect();
		
		$data=array('0'=>array('content'=>$words,'method'=>'getSenwords'));
		
		//发送请求
		$this->sendData($data);

		//接收数据
		$ret =$this->receiveData();
		
		//关闭socket请求
		$this->close();
		
		return $ret[0];
	}
	
	/**
	 * 添加一个或者多个关键词 格式 [word_level]&word 多个关键词之间用英文逗号分割
	 * java api : senWords
	 * @param string $words 1&骂死你,2&侮辱你
	 * @return boolean
	 */
	function _add($words)
	{
		//获取链接
		$this->getConnect();
		
		$data=array('0'=>array('content'=>$words,'javaApi'=>$this->_javaApis['2'],'method'=>'addConfigFile'));
		//发送请求
		$this->sendData($data);

		//接收数据
		$ret =$this->receiveData();
		
		//关闭socket请求
		$this->close();
		
		//重载敏感词
		$this->reload($this->_javaApis['2']);
	}
	
	/**
	 * 删除一个或者多个关键词 格式 word 多个关键词之间用英文逗号分割(注：不包括敏感词级别)
	 * java api : senWords
	 * @param string $words 骂死你,侮辱你
	 * @return boolean
	 */
	function _del($words)
	{
		//获取链接
		$this->getConnect();
		
		$data=array('0'=>array('content'=>$words,'javaApi'=>$this->_javaApis['2'],'method'=>'delConfigFile'));
		//发送请求
		$this->sendData($data);
		
		//接收数据
		$ret =$this->receiveData();
		
		//关闭socket请求
		$this->close();
		
		//重载敏感词
		$this->reload($this->_javaApis['2']);
	}
	
	/**
	 * 重载socket java模块的配置
	 * java api : senWords || html || request(包括senWords重载和html重载)
	 */
	function reload($javaApi)
	{
		if(!$javaApi) $javaApi=$this->_javaApis['0'];
		if($this->isJavaApi($javaApi))
		{
			//获取链接
			$this->getConnect();
		
			$data=array('0'=>array('javaApi'=>$javaApi,'method'=>'reload'));
			//发送请求
			$this->sendData($data);
			
			//接收数据
			$ret =$this->receiveData();
		
			//关闭socket请求
			$this->close();
		}
		else
		{
			throw new Exception("Socket.reload java api invalid");
		}
	}
	
	/**
	 * 未连接状态返回虚拟值
	*/
	function imitateData($data)
	{
		$ret=array();
		foreach($data as $k =>$v)
		{
			if($v['method']=='filterHtmls')
			{
				$ret[]=$v['content'];
			}
			else
			{
				$ret[$k]['hasEmail']=false;
				$ret[$k]['hasPhone']=false;
				$ret[$k]['hasQQ']=false;
				$ret[$k]['hasWords']=false;
			}
		}
		return $ret;
	}
}
